/*
 *      Author: Honrun
 */
#include "stdint.h"
#include "stdio.h"
#include "gd32f30x.h"
#include "DevicesTime.h"
#include "DevicesKey.h"


static KeyStateEnum enumKeyStateGet(uint32_t uiNewValue, uint32_t uiOldValue);
static KeyStateEnum enumKeyTimeStateGet(KeyTypeDef *ptypeKeyMachine);


KeyTypeDef g_typeKeyData;


void vKeyInit(void)
{
    /* enable the GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_GPIOE);

    gpio_bit_set(KEY_POWER_GPIO_Port,   KEY_POWER_Pin);
    gpio_bit_set(KEY_RESET_GPIO_Port,   KEY_RESET_Pin);
    gpio_bit_set(KEY_AC_GPIO_Port,      KEY_AC_Pin);
    gpio_bit_set(KEY_DC_GPIO_Port,      KEY_DC_Pin);
    gpio_bit_set(KEY_USB_GPIO_Port,     KEY_USB_Pin);
    gpio_bit_set(KEY_LAMP_GPIO_Port,    KEY_LAMP_Pin);

    /* configure key pin as input */
    gpio_init(KEY_POWER_GPIO_Port,  GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_POWER_Pin);
    gpio_init(KEY_RESET_GPIO_Port,  GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_RESET_Pin);
    gpio_init(KEY_AC_GPIO_Port,     GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_AC_Pin);
    gpio_init(KEY_DC_GPIO_Port,     GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_DC_Pin);
    gpio_init(KEY_USB_GPIO_Port,    GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_USB_Pin);
    gpio_init(KEY_LAMP_GPIO_Port,   GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, KEY_LAMP_Pin);

    g_typeKeyData.uiKeyValueGet = uiKeyValueGet;
}

/*
Return Value:   按键组合序号（头文件里有定义）
Parameters:     void
Description:    读取当前按键状态
*/
uint32_t uiKeyValueGet(void)
{
    uint32_t Key = KEY_POWER | KEY_RESET | KEY_AC | KEY_DC | KEY_USB | KEY_LAMP;
    uint8_t i = 0;

    for(i = 0; i < 8; ++i)
    {
        if(RESET != gpio_input_bit_get(KEY_POWER_GPIO_Port, KEY_POWER_Pin))
            Key &= ~KEY_POWER;
        if(RESET != gpio_input_bit_get(KEY_RESET_GPIO_Port, KEY_RESET_Pin))
            Key &= ~KEY_RESET;
        if(RESET != gpio_input_bit_get(KEY_AC_GPIO_Port, KEY_AC_Pin))
            Key &= ~KEY_AC;
        if(RESET != gpio_input_bit_get(KEY_DC_GPIO_Port, KEY_DC_Pin))
            Key &= ~KEY_DC;
        if(RESET != gpio_input_bit_get(KEY_USB_GPIO_Port, KEY_USB_Pin))
            Key &= ~KEY_USB;
        if(RESET != gpio_input_bit_get(KEY_LAMP_GPIO_Port, KEY_LAMP_Pin))
            Key &= ~KEY_LAMP;
    }

    return Key;
}

/*
 * Return:      按键状态
 * Parameters:  Value_new:新按键键值; Value_old:旧按键键值;
 * Description: 按键状态获取
 */
static KeyStateEnum enumKeyStateGet(uint32_t uiNewValue, uint32_t uiOldValue)
{
    if(uiNewValue == uiOldValue)                        /* 当前按键值与上次按键值相同 */
        return keyEqual;
    else if((uiNewValue & uiOldValue) == uiOldValue)    /* 当前按键值在上次按键值基础上增加了新按键 */
        return keyAdd;
    else if((uiNewValue | uiOldValue) == uiOldValue)    /* 当前按键值在上次按键值基础上减少了旧按键 */
        return keyCut;
    else                                                /* 当前按键值在上次按键值基础上即减少了旧按键又增加了新按键 */
        return keyAddAndCut;
}

/*
 * Return:      KeyStateEnum：按键状态机的状态
 * Parameters:  ptypeKeyMachine: 按键结构消息
 * Description: 按键状态获取
 */
static KeyStateEnum enumKeyTimeStateGet(KeyTypeDef *ptypeKeyMachine)
{
    int32_t lTimeNow = 0;

    lTimeNow = lTimeGetStamp() / 1000;

    switch((uint32_t)ptypeKeyMachine->state)
    {
        case keyAdd:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_SHORT_TIME)
            {
                ptypeKeyMachine->state &= 0x00FF;
                ptypeKeyMachine->state |= keyShort;
                return ptypeKeyMachine->state;
            }
            break;

        case keyShort | keyAdd:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_LONG_TIME)
            {
                ptypeKeyMachine->state &= 0x00FF;
                ptypeKeyMachine->state |= keyLong;
                return ptypeKeyMachine->state;
            }
            break;

        case keyLong | keyAdd:
            if((lTimeNow - ptypeKeyMachine->timePress) >= KEY_CONTINUE_TIME)
            {
                ptypeKeyMachine->state &= 0x00FF;
                ptypeKeyMachine->state |= keyContinuous;
                return ptypeKeyMachine->state;
            }
            break;

        case keyContinuous | keyAdd:
            break;

        default : break;
    }

    return keyNormal;
}

/*
 * Return:      KeyStateEnum：按键状态机的状态
 * Parameters:  ptypeKeyMachine：按键结构消息
 * Description: 按键状态机信息获取
 */
KeyStateEnum enumKeyStateMachine(KeyTypeDef *ptypeKeyMachine)
{
    uint32_t uiNewValue = 0, uiTimeNow = 0;
    KeyStateEnum enumState;

    if((ptypeKeyMachine == NULL) || (ptypeKeyMachine->uiKeyValueGet == NULL))
        return keyNormal;

    /* 键值获取 */
    if(((uiNewValue = ptypeKeyMachine->uiKeyValueGet()) != 0) || (ptypeKeyMachine->valueLast != 0))
    {
        /* 按键状态判断 */
        enumState = enumKeyStateGet(uiNewValue, ptypeKeyMachine->valueLast);

        uiTimeNow = lTimeGetStamp() / 1000;

        /* 按键状态转换 */
        switch(enumState)
        {
            /* 记录按键按下时间、按下总键值，松开按键键值清零 */
            case keyAdd:
                ptypeKeyMachine->valuePress = uiNewValue;
                ptypeKeyMachine->timePress = uiTimeNow;
                ptypeKeyMachine->valueLoosen = 0;
                ptypeKeyMachine->state = keyAdd;
                ptypeKeyMachine->valueLast = uiNewValue;
                break;

            /* 记录按键松开时间、松开总键值 */
            case keyCut:
                ptypeKeyMachine->valueLoosen |= ptypeKeyMachine->valueLast & (~uiNewValue);
                ptypeKeyMachine->timeLoosen = uiTimeNow;
                ptypeKeyMachine->state &= ~0x00FF;
                ptypeKeyMachine->state |= keyCut;
                ptypeKeyMachine->valueLast = uiNewValue;
                return ptypeKeyMachine->state;

            /* 记录按键按下时间、按下总键值、松开时间、松开总键值 */
            case keyAddAndCut:
                ptypeKeyMachine->valuePress = uiNewValue;
                ptypeKeyMachine->timePress = uiTimeNow;
                ptypeKeyMachine->valueLoosen |= ptypeKeyMachine->valueLast & (~uiNewValue);
                ptypeKeyMachine->timeLoosen = uiTimeNow;
                ptypeKeyMachine->valueLast = uiNewValue;
                break;

            case keyEqual:
                return enumKeyTimeStateGet(ptypeKeyMachine);

            default: break;
        }
    }

    return keyNormal;
}
